#include "Plot3D.h"
#include <fstream>
namespace{
    QString tr(const char* val)
    {
        return QObject::tr(val);
    }

    void setCheckable(QActionGroup* ag)
    {
        QList<QAction*> tmplist = ag->actions();
        for (QList<QAction*>::iterator it=tmplist.begin(); it!=tmplist.end(); ++it)
            (*it)->setCheckable(true);
    }

}
Plot_3D::Plot_3D(QWidget *parent):
        SurfacePlot(parent)
{

}

void Plot_3D::setupWorkaround(QWidget *mw)
{
    // actions

    animation = new QAction(QIcon(":/png/pics/PNG/movie.png"), tr("Animation"), mw);
    animation->setCheckable(true);
    dump = new QAction(QIcon(":/png/pics/PNG/savecontent.png"), "", mw);

    coord = new QActionGroup(mw);
    Box = new QAction(QIcon(":/png/pics/PNG/box.png"), "", coord);
    Frame = new QAction(QIcon(":/png/pics/PNG/frame.png"), "", coord);
    None = new QAction(QIcon(":/png/pics/PNG/grid.png"), "", coord);
    setCheckable(coord);

    grids = new QActionGroup(mw);
    front = new QAction(QIcon(":/png/pics/PNG/gridfr.png"), "", grids);
    back = new QAction(QIcon(":/png/pics/PNG/gridb.png"), "", grids);
    right = new QAction(QIcon(":/png/pics/PNG/gridr.png"), "", grids);
    left = new QAction(QIcon(":/png/pics/PNG/gridl.png"), "", grids);
    ceil = new QAction(QIcon(":/png/pics/PNG/gridc.png"), "", grids);
    floor = new QAction(QIcon(":/png/pics/PNG/gridf.png"), "", grids);
    grids->setExclusive(false);
    setCheckable(grids);

    plotstyle = new QActionGroup(mw);
    pointstyle = new QAction(QIcon(":/png/pics/PNG/scattered.png"), "", plotstyle);
    wireframe = new QAction(QIcon(":/png/pics/PNG/wireframe.png"), "", plotstyle);
    hiddenline = new QAction(QIcon(":/png/pics/PNG/hiddenline.png"), "", plotstyle);
    polygon = new QAction(QIcon(":/png/pics/PNG/polygon.png"), "", plotstyle);
    filledmesh = new QAction(QIcon(":/png/pics/PNG/filledmesh.png"), "", plotstyle);
    nodata = new QAction(QIcon(":/png/pics/PNG/nodata.png"), "", plotstyle);
    setCheckable(plotstyle);

    floorstyle = new QActionGroup(mw);
    floordata = new QAction(QIcon(":/png/pics/PNG/floordata.png"), "", floorstyle);
    flooriso = new QAction(QIcon(":/png/pics/PNG/flooriso.png"), "", floorstyle);
    floornone = new QAction(QIcon(":/png/pics/PNG/floorempty.png"), "", floorstyle);
    setCheckable(floorstyle);

    normals = new QAction(QIcon(":/png/pics/PNG/normals.png"), "", mw);
    normals->setCheckable(true);

    color = new QActionGroup(mw);
    axescolor = new QAction(tr("&Axes"), color);
    backgroundcolor = new QAction(tr("&Background"), color);
    meshcolor = new QAction(tr("&Mesh"), color);
    numbercolor = new QAction(tr("&Numbers"), color);
    labelcolor = new QAction(tr("&Label"), color);
    titlecolor = new QAction(tr("Caption"), color);
    datacolor = new QAction(tr("Data color"), color);
    resetcolor = new QAction(tr("&Reset"), color);

    font = new QActionGroup(mw);
    numberfont = new QAction(tr("&Scale numbering"), font);
    labelfont = new QAction(tr("&Axes label"), font);
    titlefont = new QAction(tr("&Caption"), font);
    resetfont = new QAction(tr("&Reset"), font);


    // toolbars


    filetypeCB = new QComboBox;
    functionCB = new QComboBox;
    psurfaceCB = new QComboBox;
    SPL_Plot_3D_frame = new QFrame;


    csToolbar = new QToolBar( QString(""), mw );
    csToolbar->setMovable( true );
    //csToolbar->addAction(dump);
    //csToolbar->addWidget(filetypeCB);
    csToolbar->addWidget(functionCB);
    csToolbar->addWidget(psurfaceCB);
    csToolbar->addAction(animation);
    csToolbar->addActions(coord->actions());
    csToolbar->addActions(grids->actions());
    csToolbar->addActions(plotstyle->actions());
    csToolbar->addActions(floorstyle->actions());
    csToolbar->addAction(normals);



    // menubar
    /*menubar = mw->menuBar();//new QMenuBar();
    filemenu = menubar->addMenu("&File");
      filemenu->addAction(openFile);
      filemenu->addAction(openMeshFile);
      filemenu->addAction(animation);
      filemenu->addAction(Exit);
    colormenu = menubar->addMenu(tr("&Color"));    
      colormenu->addActions(color->actions());
    fontmenu = menubar->addMenu(tr("&Fonts"));    
      fontmenu->addActions(font->actions());
  */
    // mw->addToolBar(mainToolbar);
    // mw->addToolBar(csToolbar);


    functionCB->clear();
    functionCB->addItem( tr( "---" ) );
    functionCB->addItem( tr( "Hat" ) );
    functionCB->addItem( tr( "Rosenbrock" ) );
    functionCB->addItem( tr( "Saddle" ) );
    functionCB->addItem( tr( "Sombrero" ) );
    functionCB->addItem( tr( "Ripple" ) );
    functionCB->setToolTip(tr( "Display function" ) );
    psurfaceCB->clear();
    psurfaceCB->addItem( tr( "---" ) );
    psurfaceCB->addItem( tr( "Torus" ) );
    psurfaceCB->addItem( tr( "Seashell" ) );
    psurfaceCB->addItem( tr( "Boy" ) );
    psurfaceCB->addItem( tr( "Dini" ) );
    psurfaceCB->addItem( tr( "Cone" ) );
    psurfaceCB->setToolTip(tr( "Display parametric surface. Turn Lighting on for better quality."));
    QGridLayout *layout = new QGridLayout;
    layout->addWidget(csToolbar);

    layout->addWidget(SPL_Plot_3D_frame);

    mw->setLayout(layout);
    // QObject::connect(Exit, SIGNAL(triggered()), mw, SLOT(close()));
}



void Plot_3D::createFunction(QString const& name)
{
    dataWidget->makeCurrent();

    dataWidget->legend()->setScale(Qwt3D::LINEARSCALE);
    for (unsigned i=0; i!=dataWidget->coordinates()->axes.size(); ++i)
    {
        dataWidget->coordinates()->axes[i].setMajors(7);
        dataWidget->coordinates()->axes[i].setMinors(5);
    }

    if (name == QString("Rosenbrock"))
    {
        qDebug(name.toAscii());
        Rosenbrock rosenbrock(*dataWidget);

        rosenbrock.setMesh(50,51);
        rosenbrock.setDomain(-1.73,1.55,-1.5,1.95);
        rosenbrock.setMinZ(-100);

        rosenbrock.create();
        qDebug("rosenbrock.create()");
        dataWidget->coordinates()->axes[Z1].setScale(LOG10SCALE);
        dataWidget->coordinates()->axes[Z2].setScale(LOG10SCALE);
        dataWidget->coordinates()->axes[Z3].setScale(LOG10SCALE);
        dataWidget->coordinates()->axes[Z4].setScale(LOG10SCALE);
        dataWidget->legend()->setScale(LOG10SCALE);
        qDebug("setScale");
    }
    else if (name == QString("Hat"))
    {
        Hat hat(*dataWidget);

        hat.setMesh(51,72);
        hat.setDomain(-1.5,1.5,-1.5,1.5);
        hat.create();
    }
    else if (name == QString("Ripple"))
    {
        Ripple ripple(*dataWidget);
        ripple.setMesh(120,120);
        ripple.create();
    }
    else if (name == QString("Saddle"))
    {
        Saddle saddle;

        saddle.setMesh(71,71);
        double dom = 2.5;
        saddle.setDomain(-dom, dom, -dom, dom);
        saddle.assign(*dataWidget);
        saddle.create();
    }
    else if (name == QString("Sombrero"))
    {
        Mex mex;

        mex.setMesh(91,91);
        double dom = 15;
        mex.setDomain(-dom, dom, -dom, dom);
        mex.create(*dataWidget);
    }
    qDebug("define a b");
    //double a = dataWidget->facets().first;
    //double b = dataWidget->facets().second;

    //dimWidget->setText(QString("Cells ") + QString::number(a*b)
    //                   + " (" + QString::number(a) + "x" + QString::number(b) +")" );
    qDebug("setText");
    //updateColorLegend(7,5);

    dataWidget->coordinates()->axes[X1].setLabelString(QString("X1"));
    dataWidget->coordinates()->axes[X2].setLabelString(QString("X2"));
    dataWidget->coordinates()->axes[X3].setLabelString(QString("X3"));
    dataWidget->coordinates()->axes[X4].setLabelString(QString("X4"));

    dataWidget->coordinates()->axes[Y1].setLabelString(QString("Y1"));
    dataWidget->coordinates()->axes[Y2].setLabelString(QString("Y2"));
    dataWidget->coordinates()->axes[Y3].setLabelString(QString("Y3"));
    dataWidget->coordinates()->axes[Y4].setLabelString(QString("Y4"));

    dataWidget->coordinates()->axes[Z1].setLabelString(QString("Z1"));
    dataWidget->coordinates()->axes[Z2].setLabelString(QString("Z2"));
    dataWidget->coordinates()->axes[Z3].setLabelString(QString("Z3"));
    dataWidget->coordinates()->axes[Z4].setLabelString(QString("Z4"));

    qDebug("setlabel axes");
    pickCoordSystem(activeCoordSystem);
    qDebug("pickCoordSystem");
}

void Plot_3D::pickCoordSystem( QAction* action)
{
    if (!action || !dataWidget)
        return;

    activeCoordSystem = action;

    dataWidget->setTitle("QwtPlot_3D (Use Ctrl-Alt-Shift-LeftBtn-Wheel or keyboard)");

    if (!dataWidget->hasData())
    {
        double l = 0.6;
        dataWidget->createCoordinateSystem(Triple(-l,-l,-l), Triple(l,l,l));
        for (unsigned i=0; i!=dataWidget->coordinates()->axes.size(); ++i)
        {
            dataWidget->coordinates()->axes[i].setMajors(4);
            dataWidget->coordinates()->axes[i].setMinors(5);
        }
    }

    if (action == Box || action == Frame)
    {
        if (action == Box)
            dataWidget->setCoordinateStyle(BOX);
        if (action == Frame)
            dataWidget->setCoordinateStyle(FRAME);
        grids->setEnabled(true);
    }
    else if (action == None)
    {
        dataWidget->setTitle("QwtPlot_3D (Use Ctrl-Alt-Shift-LeftBtn-Wheel or keyboard)");
        dataWidget->setCoordinateStyle(NOCOORD);
        grids->setEnabled(false);
    }
}



void Plot_3D::createPSurface(QString const& name)
{
    dataWidget->makeCurrent();
    if (name == QString("Torus"))
    {
        Torus sf(*dataWidget);
        sf.create();
    }
    else if (name == QString("Seashell"))
    {
        Seashell ss(*dataWidget);
        ss.create();
    }
    else if (name == QString("Boy"))
    {
        Boy boy(*dataWidget);
        boy.create();
    }
    else if (name == QString("Dini"))
    {
        Dini dini(*dataWidget);
        dini.create();
    }
    else if (name == QString("Cone"))
    {
        TripleField conepos;
        CellField conecell;
        createCone(conepos,conecell);
        dataWidget->loadFromData(conepos, conecell);
    }
    for (unsigned i=0; i!=dataWidget->coordinates()->axes.size(); ++i)
    {
        dataWidget->coordinates()->axes[i].setMajors(7);
        dataWidget->coordinates()->axes[i].setMinors(5);
    }

   /* double a = dataWidget->facets().first;
    double b = dataWidget->facets().second;

    dimWidget->setText(QString("Cells ") + QString::number(a*b)
                       + " (" + QString::number(a) + "x" + QString::number(b) +")" );
*/
    //updateColorLegend(7,5);

    dataWidget->coordinates()->axes[X1].setLabelString(QString("X1"));
    dataWidget->coordinates()->axes[X2].setLabelString(QString("X2"));
    dataWidget->coordinates()->axes[X3].setLabelString(QString("X3"));
    dataWidget->coordinates()->axes[X4].setLabelString(QString("X4"));

    dataWidget->coordinates()->axes[Y1].setLabelString(QString("Y1"));
    dataWidget->coordinates()->axes[Y2].setLabelString(QString("Y2"));
    dataWidget->coordinates()->axes[Y3].setLabelString(QString("Y3"));
    dataWidget->coordinates()->axes[Y4].setLabelString(QString("Y4"));

    dataWidget->coordinates()->axes[Z1].setLabelString(QString("Z1"));
    dataWidget->coordinates()->axes[Z2].setLabelString(QString("Z2"));
    dataWidget->coordinates()->axes[Z3].setLabelString(QString("Z3"));
    dataWidget->coordinates()->axes[Z4].setLabelString(QString("Z4"));

    pickCoordSystem(activeCoordSystem);
}
void Plot_3D::pickPlotStyle( QAction* action )
{
    if (!action || !dataWidget)
        return;

    if (action == polygon)
    {
        dataWidget->setPlotStyle(FILLED);
    }
    else if (action == filledmesh)
    {
        dataWidget->setPlotStyle(FILLEDMESH);
    }
    else if (action == wireframe)
    {
        dataWidget->setPlotStyle(WIREFRAME);
    }
    else if (action == hiddenline)
    {
        dataWidget->setPlotStyle(HIDDENLINE);
    }
    else if (action == pointstyle)
    {

        dataWidget->setPlotStyle(Qwt3D::POINTS);
        //    Cone d(len,32);
        //    CrossHair d(0.003,0,true,false);
        //    dataWidget->setPlotStyle(d);
    }
    else
    {
        dataWidget->setPlotStyle(NOPLOT);
    }
    dataWidget->updateData();
    dataWidget->updateGL();
}

void Plot_3D::pickFloorStyle( QAction* action )
{
    if (!action || !dataWidget)
        return;

    if (action == floordata)
    {
        dataWidget->setFloorStyle(FLOORDATA);
    }
    else if (action == flooriso)
    {
        dataWidget->setFloorStyle(FLOORISO);
    }
    else
    {
        dataWidget->setFloorStyle(NOFLOOR);
    }

    dataWidget->updateData();
    dataWidget->updateGL();
}





void Plot_3D::setLeftGrid(bool b)
{
    setGrid(Qwt3D::LEFT,b);
}
void Plot_3D::setRightGrid(bool b)
{
    setGrid(Qwt3D::RIGHT,b);
}
void Plot_3D::setCeilGrid(bool b)
{
    setGrid(Qwt3D::CEIL,b);
}
void Plot_3D::setFloorGrid(bool b)
{
    setGrid(Qwt3D::FLOOR,b);
}
void Plot_3D::setFrontGrid(bool b)
{
    setGrid(Qwt3D::FRONT,b);
}
void Plot_3D::setBackGrid(bool b)
{
    setGrid(Qwt3D::BACK,b);
}

void Plot_3D::setGrid(Qwt3D::SIDE s, bool b)
{
    if (!dataWidget)
        return;

    int sum = dataWidget->coordinates()->grids();

    if (b)
        sum |= s;
    else
        sum &= ~s;

    dataWidget->coordinates()->setGridLines(sum!=Qwt3D::NOSIDEGRID, sum!=Qwt3D::NOSIDEGRID, sum);
    dataWidget->updateGL();
}

void Plot_3D::resetColors()
{
    if (!dataWidget)
        return;

    const RGBA axc = RGBA(0,0,0,1);
    const RGBA bgc = RGBA(1.0,1.0,1.0,1.0);
    const RGBA msc = RGBA(0,0,0,1);
    const RGBA nuc = RGBA(0,0,0,1);
    const RGBA lbc = RGBA(0,0,0,1);
    const RGBA tc = RGBA(0,0,0,1);

    dataWidget->coordinates()->setAxesColor(axc);
    dataWidget->setBackgroundColor(bgc);
    dataWidget->setMeshColor(msc);
    dataWidget->updateData();
    dataWidget->coordinates()->setNumberColor(nuc);
    dataWidget->coordinates()->setLabelColor(lbc);
    dataWidget->setTitleColor(tc);

    col_ = new StandardColor(dataWidget);
    dataWidget->setDataColor(col_);
    dataWidget->updateData();
    dataWidget->updateNormals();
    dataWidget->updateGL();
}





void Plot_3D::setStandardView()
{
    dataWidget->setRotation(30,0,15);
    dataWidget->setViewportShift(0.05,0);
    dataWidget->setScale(1,1,1);
    dataWidget->setZoom(0.95);
}

void Plot_3D::dumpImage()
{
    static int counter = 0;
    if (!dataWidget)
        return;
    QString name;

    name = QString("dump_") + QString::number(counter++) + ".";

    if (filetype_ == "PS_GZ")
        name += "ps.gz";
    else if (filetype_ == "EPS_GZ")
        name += "eps.gz";
    else
        name += filetype_;

#if QT_VERSION < 0x040000
    IO::save(dataWidget, name.lower(), filetype_);
#else
    VectorWriter* vw = (VectorWriter*)IO::outputHandler("PDF");
    if (vw)
        vw->setSortMode(VectorWriter::BSPSORT);
    IO::save(dataWidget, name.toLower(), filetype_);
#endif
}

/*!
  Turns animation on or off
*/
void Plot_3D::toggleAnimation(bool val)
{
    if ( val )
    {
        timer->start( redrawWait ); // Wait this many msecs before redraw
    }
    else
    {
        timer->stop();
    }
}

void Plot_3D::rotate()
{
    if (!dataWidget)
        return;

    dataWidget->setRotation(
            int(dataWidget->xRotation() + 1) % 360,
            int(dataWidget->yRotation() + 1) % 360,
            int(dataWidget->zRotation() + 1) % 360
            );
}

void
        Plot_3D::toggleProjectionMode(bool val)
{
    dataWidget->setOrtho(val);
}

void
        Plot_3D::toggleColorLegend(bool val)
{
    legend_ = val;
    dataWidget->showColorLegend(val);
}

void
        Plot_3D::toggleAutoScale(bool val)
{
    dataWidget->coordinates()->setAutoScale(val);
    dataWidget->updateGL();
}

void
        Plot_3D::toggleShader(bool val)
{
    if (val)
        dataWidget->setShading(GOURAUD);
    else
        dataWidget->setShading(FLAT);
}

void
        Plot_3D::setPolygonOffset(int val)
{
    dataWidget->setPolygonOffset(val / 10.0);
    dataWidget->updateData();
    dataWidget->updateGL();
}

void
        Plot_3D::showRotate(double x, double y, double z)
{
    rotateLabel->setText(" Angles ("  + QString::number(x,'g',3) + " ,"
                         + QString::number(y,'g',3) + " ,"
                         + QString::number(z,'g',3) + ")");
}
void
        Plot_3D::showShift(double x, double y)
{
    shiftLabel->setText(" Shifts (" + QString::number(x,'g',3) + " ,"
                        + QString::number(y,'g',3) + " )"
                        );
}
void
        Plot_3D::showScale(double x, double y, double z)
{
    scaleLabel->setText(" Scales (" + QString::number(x,'g',3) + " ,"
                        + QString::number(y,'g',3) + " ,"
                        + QString::number(z,'g',3) + ")");
}
void
        Plot_3D::showZoom(double z)
{
    zoomLabel->setText(" Zoom "  + QString::number(z,'g',3));
}



void
        Plot_3D::showNormals(bool val)
{
    dataWidget->showNormals(val);
    dataWidget->updateNormals();
    dataWidget->updateGL();
}

void
        Plot_3D::setNormalLength(int val)
{
    dataWidget->setNormalLength(val / 400.);
    dataWidget->updateNormals();
    dataWidget->updateGL();
}

void
        Plot_3D::setNormalQuality(int val)
{
    dataWidget->setNormalQuality(val);
    dataWidget->updateNormals();
    dataWidget->updateGL();
}





